package view

import (
	"cloudops/src/common"
	"cloudops/src/config"
	"cloudops/src/models"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
	"go.uber.org/zap"
	"strconv"
)

func createJobTask(c *gin.Context) {
	sc := c.MustGet(common.GIN_CTX_CONFIG_CONFIG).(*config.ServerConfig)
	var reqObj models.JobTask
	err := c.ShouldBindJSON(&reqObj)
	if err != nil {
		sc.Logger.Error("解析新增任务执行请求失败", zap.Any("任务", reqObj), zap.Error(err))
		common.FailWithMessage(err.Error(), c)
		return
	}

	//字段校验
	err = validate.Struct(reqObj)
	if err != nil {
		if errors, ok := err.(validator.ValidationErrors); ok {
			common.ReqBadFailWithWithDetailed(
				gin.H{
					"翻译前": err.Error(),
					"翻译后": errors.Translate(trans),
				},
				"请求出错",
				c,
			)
			return
		}
		common.FailWithMessage(err.Error(), c)
		return
	}

	userName := c.MustGet(common.GIN_CTX_JWT_USER_NAME).(string)
	dbUser, err := models.GetUserByUserName(userName)
	if err != nil {
		sc.Logger.Error("通过token解析到userName去数据库库中查找用户失败",
			zap.Error(err),
		)
		common.ReqBadFailWithMessage(fmt.Sprintf("通过token解析到的userName去数据库中找User失败:%v", err.Error()), c)
		return
	}
	reqObj.UserID = dbUser.ID

	// treeNode是必须的，直接根据 HostIds 那么直接从node上获取
	var hostIds []string
	err = json.Unmarshal([]byte(reqObj.HostsIdsRaw), &hostIds)
	if err != nil {
		errMsg := fmt.Sprintf("通过token解析到的hostIds去数据库中找User失败:%v", err.Error())
		sc.Logger.Error(errMsg, zap.Error(err))
		common.ReqBadFailWithMessage(errMsg, c)
		return
	}

	// 机器不能为空
	if len(hostIds) == 0 {
		errMsg := fmt.Sprintf("通过HostsIdsRaw解析到的hostIds为空")
		sc.Logger.Error(errMsg,
			zap.Error(err),
		)
		common.ReqBadFailWithMessage(errMsg, c)
		return
	}

	hostIdInt := []int{}
	for _, idS := range hostIds {
		intS, _ := strconv.Atoi(idS)
		hostIdInt = append(hostIdInt, intS)
	}
	hosts, err := models.GetResourceEcsByIdsWithLimitOffset(hostIdInt, 1000, 0)
	if err != nil {
		errMsg := fmt.Sprintf("通过hostIds获取机器失败")
		sc.Logger.Error(errMsg,
			zap.Error(err),
		)
		common.ReqBadFailWithMessage(errMsg, c)
		return
	}

	hostIps := []string{}
	for _, host := range hosts {
		hostIps = append(hostIps, host.IpAddr)
	}
	hostIpRaw, _ := json.Marshal(hostIps)
	reqObj.TotalNum = len(hostIps)
	reqObj.HostsRaw = string(hostIpRaw)
	reqObj.Status = common.JOB_STATUS_PENING

	// 级联创建任务
	err = reqObj.JobTaskCreate()
	if err != nil {
		sc.Logger.Error("任务执行创建失败", zap.Any("任务", reqObj), zap.Error(err))
		common.FailWithMessage(fmt.Sprintf("任务执行创建失败:%v", err.Error()), c)
		return
	}
	common.OkWithMessage("任务执行创建成功", c)
}

func getJobTaskList(c *gin.Context) {
	sc := c.MustGet(common.GIN_CTX_CONFIG_CONFIG).(*config.ServerConfig)
	currentPage, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	pageSize, _ := strconv.Atoi(c.DefaultQuery("pageSize", "100"))

	offset := 0
	limit := 0
	limit = pageSize
	if currentPage > 1 {
		offset = (currentPage - 1) * limit
	}

	searchUserID := c.DefaultQuery("UserID", "")
	searchUserIDInt, _ := strconv.Atoi(searchUserID)
	searchName := c.DefaultQuery("name", "")

	// 获取所有的任务
	objs, err := models.GetJobTaskAll()
	if err != nil {
		sc.Logger.Error("GetJobTaskAll，获取任务列表失败", zap.Error(err))
		common.FailWithMessage(fmt.Sprintf("获取任务列表失败:%v", err.Error()), c)
		return
	}

	allIds := []int{}
	for _, obj := range objs {
		obj := obj

		if searchName != "" && obj.Title != searchName {
			continue
		}

		if searchUserID != "" && int(obj.UserID) != searchUserIDInt {
			continue
		}
		allIds = append(allIds, int(obj.ID))
	}

	if len(allIds) == 0 {
		common.OkWithDetailed(allIds, "ok", c)
		return
	}

	objs, err = models.GetJobTaskByIdsWithLimitOffset(allIds, limit, offset)
	if err != nil {
		sc.Logger.Error("GetJobTaskByIdsWithLimitOffset，获取任务列表失败", zap.Error(err))
		common.FailWithMessage(fmt.Sprintf("获取任务列表失败:%v", err.Error()), c)
		return
	}

	for _, obj := range objs {
		obj.FillFrontAllData()
	}

	resp := &ResponseResourceCommon{
		Total: len(allIds),
		Items: objs,
	}

	common.OkWithDetailed(resp, "获取任务列表成功", c)
}

func getJobTaskOne(c *gin.Context) {
	sc := c.MustGet(common.GIN_CTX_CONFIG_CONFIG).(*config.ServerConfig)
	id := c.Param("id")
	intVar, _ := strconv.Atoi(id)
	dbObj, err := models.GetJobTaskById(intVar)
	if err != nil {
		sc.Logger.Error("GetJobTaskById，根据ID获取任务实力失败", zap.Any("任务实例", id), zap.Error(err))
		common.FailWithMessage(fmt.Sprintf("根据ID获取任务实例失败:%v", err.Error()), c)
		return
	}
	dbObj.FillFrontAllData()
	common.OkWithDetailed(dbObj, "根据ID获取任务实例成功", c)
}

func actionJobTaskOne(c *gin.Context) {
	sc := c.MustGet(common.GIN_CTX_CONFIG_CONFIG).(*config.ServerConfig)
	id := c.Param("id")
	intVar, _ := strconv.Atoi(id)
	dbObj, err := models.GetJobTaskById(intVar)
	if err != nil {
		sc.Logger.Error("GetJobTaskById，根据ID获取任务实例失败", zap.Any("任务实例", id), zap.Error(err))
		common.FailWithMessage(fmt.Sprintf("根据ID获取任务实例失败:%v", err.Error()), c)
		return
	}
	action := c.Query("action")
	nextStatus, exist := common.JOB_ACTION_NEXT_STATUS_MAP[action]
	if !exist {
		sc.Logger.Error("传入的动作错误", zap.Any("任务执行", id), zap.Error(err))
		common.FailWithMessage(err.Error(), c)
		return
	}

	if action == common.AGENT_TASK_ACTION_KILL {
		dbObj.Status = common.JOB_STATUS_KILLED
	}

	sc.Logger.Info("任务执行操作",
		zap.Any("id", id),
		zap.Any("action", action),
		zap.Any("nextStatus", nextStatus),
	)
	userName := c.MustGet(common.GIN_CTX_JWT_USER_NAME).(string)
	_ = dbObj.UpdateFlowData(action, userName)
	dbObj.Status = nextStatus
	err = dbObj.JobTaskUpdateOne()
	if err != nil {
		sc.Logger.Error("更新任务执行失败",
			zap.Any("任务执行", id), zap.Error(err))
		common.FailWithMessage(fmt.Sprintf("任务执行操作失败:%v", err.Error()), c)
		return
	}
	common.OkWithMessage("任务执行操作成功", c)
}
